'use strict';

const modal = document.querySelector('.modal');
const overlay = document.querySelector('.overlay');
const btnCloseModal = document.querySelector('.btn--close-modal');
const btnsOpenModal = document.querySelectorAll('.btn--show-modal');
const btnScrollTo = document.querySelector('.btn--scroll-to')
const section1 = document.querySelector('#section--1')
// 选择tabs所有子组件
const tabs = document.querySelectorAll('.operations__tab');
// 选择tabs父组件
const tabsContainer = document.querySelector('.operations__tab-container')
// 选择tabs所有内容子组件
const tabsContent = document.querySelectorAll('.operations__content');
const nav = document.querySelector('.nav');
///////////////////////////////////////
// Modal window

const openModal = function (e) {
  e.preventDefault();
  modal.classList.remove('hidden');
  overlay.classList.remove('hidden');
};

const closeModal = function (e) {
  e.preventDefault();
  modal.classList.add('hidden');
  overlay.classList.add('hidden');
};

btnsOpenModal.forEach(btn => btn.addEventListener('click', openModal));


btnCloseModal.addEventListener('click', closeModal);
overlay.addEventListener('click', closeModal);

document.addEventListener('keydown', function (e) {
  if (e.key === 'Escape' && !modal.classList.contains('hidden')) {
    closeModal();
  }
});

///////////////////////////////////////
// P176、实现平滑滚动
btnScrollTo.addEventListener('click', function (e) {
  const s1Coords = section1.getBoundingClientRect(); // section1元素的大小及相对视口的位置
  console.log(s1Coords);
  console.log(e.target.getBoundingClientRect()); // 点击事件元素的大小及相对视口的位置
  console.log(window.pageXOffset, window.pageYOffset); // 页面水平垂直滚动的像素
  console.log(document.documentElement.clientHeight, document.documentElement.clientWidth); // 当前窗口的高度和宽度

  // window.scrollTo(s1Coords.left, s1Coords.top); // 页面滚动到某个位置（此时只用了section1距离窗口顶部的距离）
  // window.scrollTo(s1Coords.left + window.pageXOffset, s1Coords.top + window.pageYOffset); // 页面滚动到某个位置
  // window.scrollTo({
  //   left: s1Coords.left + window.pageXOffset,
  //   top: s1Coords.top + window.pageYOffset,
  //   behavior: 'smooth'
  // }); // 页面平滑滚动到某个位置

  section1.scrollIntoView({ behavior: 'smooth' }); // 滚动元素的父容器，使被调用的元素对用户可见
});

///////////////////////////////////////
// P180、事件委托实现页面导航
// 页面导航
// 当子标签少的使用方法
// document.querySelectorAll('.nav__link').forEach(e => {
//   e.addEventListener('click', function (e) {
//     // 阻止默认事件
//     e.preventDefault();
//     // 获取需要滚到的区域的id
//     const id = this.getAttribute('href');
//     console.log(id);
//     document.querySelector(id).scrollIntoView({ behavior: 'smooth' })
//   })
// });

// 以上方法，如果有一万个元素使用forEach会严重消耗性能，此时可以使用事件委托方式减少性能的消耗
// 获取父元素并且添加点击事件
document.querySelector('.nav__links').addEventListener("click", function (e) {
  e.preventDefault();
  const target = e.target
  if (target.classList.contains('nav__link')) {
    const id = target.getAttribute('href');
    document.querySelector(id).scrollIntoView({ behavior: 'smooth' })
  }
})

// P182、构建选项卡组件
// 事件委托
tabsContainer.addEventListener('click', function (e) {
  // 选择被选中的组件
  const clicked = e.target.closest('.operations__tab');

  // 移除激活class
  tabs.forEach(t => t.classList.remove('operations__tab--active'))
  tabsContent.forEach(t => t.classList.remove('operations__content--active'))

  // 激活tab
  clicked.classList.add('operations__tab--active');

  // 激活tab内容, 通过tab组件的 data-tab
  document
    .querySelector(`.operations__content--${clicked.dataset.tab}`)
    .classList.add('operations__content--active');
})

// 菜单淡入淡出动画
// 公共方法
const handleHover = function (e) {
  // 如果目标事件的类名包括nav__link
  if (e.target.classList.contains('nav__link')) {
    const link = e.target; // 目标事件
    // 选择兄弟元素——通过匹配目标事件最近的祖先元素
    const siblings = link.closest('.nav').querySelectorAll('.nav__link'); // a标签
    const logo = link.closest('.nav').querySelector('img'); // img标签
    // 循环匹配到的链接元素不是目标事件，透明度为0.5
    siblings.forEach(el => { if (el !== link) el.style.opacity = this; })
    // logo直接透明度为0.5
    logo.style.opacity = this;
  }
}

// 事件委托
// 传递参数给公共方法
// 鼠标移入
nav.addEventListener('mouseover', handleHover.bind(0.5));
// 鼠标移出
nav.addEventListener('mouseout', handleHover.bind(1));

// P184、实现粘性导航
// // getBoundingClientRect提供了元素的大小及其相对于视口的位置
// const initialCoords = section1.getBoundingClientRect().top; // section1的开始纵坐标
// // 返回文档在垂直方向已滚动的像素值。
// window.addEventListener('scroll', function () {
//   // 如果当前文档的纵坐标大于section1，给导航栏添加sticky类（固定定位）
//   if (window.scrollY > initialCoords) nav.classList.add('sticky');
//   // 否则移除sticky类
//   else nav.classList.remove('sticky');
// })

// P185(a)、Intersection Observer API
// // 观察器的回调函数
// const obsCallback = function (entries, observer) {
//   // 解构
//   const [entry] = entries; // 数组下标为 0 的元素——第一个元素
//   const { intersectionRatio, isIntersecting } = entry
//   // 当目标元素出现在视口区域的 0 或者 0.1左右 ,时打印，反之不打印
//   console.log(intersectionRatio);
//   // 在目标元素在视口区域 0或者 0.1 左右打印，大于 0.1 打印true，小于 0.1 或者为 0，大于false
//   console.log(isIntersecting);
// }
// // 控制什么时候调用观察器的回调
// const obsOption = {
//   root: null, // 根元素，null表示视口
//   threshold: 0.1 // 阈值，当目标元素在视口的百分之 10 或者百分之 0 的时候调用观察器的回调
// }
// // 创建交叉观察器API
// const observer = new IntersectionObserver(obsCallback, obsOption);
// // 观察器的方法，参数是目标元素（要观察的元素）
// observer.observe(section1);

// P185(b)、粘性导航
// 当页面滚动到距离 id 为 section1 的元素有一个 导航栏高度 时，导航栏显示并粘性布局——定位在顶部
const header = document.querySelector('.header'); // 获取header元素
const navHeight = nav.getBoundingClientRect().height; // 提供了元素的大小及其相对于视口的位置。
// 观察器的回调
const stickNav = function (entries) {
  const [entry] = entries; // 解构出需要用到的对象
  // 当目标元素达到参数的规定距离导航栏粘性布局
  if (!entry.isIntersecting) nav.classList.add('sticky');
  // 否则移除粘性布局
  else nav.classList.remove('sticky');
}
// 创建一个监听器
const observer = new IntersectionObserver(stickNav, {
  root: null, // 视口
  threshold: 0, // 阈值为0，就是看不见header
  rootMargin: `-${navHeight}px` // 距离 id 为 section1 的元素有一个导航栏高度
});
// 监听器调用observe方法，传入目标元素
observer.observe(header);

// P186、滚动显示元素
// 获取所有需要滚动显示的元素
const allSections = document.querySelectorAll('.section');

// 观察器的回调
const revealSection = function (entries, observer) {
  // 解构
  const [entry] = entries;
  const { isIntersecting, target } = entry; // 元素是否在视口内，当前元素
  if (!isIntersecting) return; // 当目标元素不在视口的百分之十五时不移除透明类
  target.classList.remove('section--hidden'); // 当目标元素在视口的百分之十五时移除透明类
  observer.unobserve(target); // 停止观察器事件
};

// 创建观察器
const sectionObserver = new IntersectionObserver(revealSection, {
  root: null, // 视口
  threshold: 0.15, // 当目标元素在视口的百分之十五调用观察器回调
});

// 循环需要滚动的元素然后处理
allSections.forEach(function (section) {
  sectionObserver.observe(section); // 观察当前目标元素，调用根据条件观察器回调
  // section.classList.add('section--hidden'); // 直接给当前目标元素添加透明类
});

// P187、延时加载图片
// 获取所有需要加载的图片元素
const imgTargets = document.querySelectorAll('img[data-src]'); // 用于选择具有 data-src 属性的 <img> 元素。

// 观察器的回调
const loadImg = function (entries, observer) {
  // 解构
  const [entry] = entries;
  const { isIntersecting, target } = entry; // 元素是否在视口内，当前元素
  if (!isIntersecting) return; // 当目标元素不在视口内时不移除 lazy-img 类
  // 将 src 替换为 data-src
  target.src = target.dataset.src;
  // 图片加载监听事件，图片加载完成时，移除 lazy-img 类
  target.addEventListener('load', function () {
    target.classList.remove('lazy-img'); // 当滚动到距离图片高度时移除透明类
  })
  observer.unobserve(target); // 停止观察器事件
};

// 创建观察器
const imgObserver = new IntersectionObserver(loadImg, {
  root: null,// 视口
  threshold: 0,// 当目标元素在视口的百分之十五调用观察器回调
  rootMargin: '200px' // 视口滚动到距离图片高度的距离时调用观察者回调(此时为什么和之前的导航栏不一样，因为导航栏脱离了文本流)
});

// 循环需要滚动的元素然后处理
imgTargets.forEach(img => imgObserver.observe(img)); // 观察当前目标元素，调用根据条件观察器回调

// P188、构建滑块（幻灯片）组件(第 1 部分)
// 元素选择
const slides = document.querySelectorAll('.slide')
const slideLeft = document.querySelector('.slider__btn--left')
const slideRight = document.querySelector('.slider__btn--right')
const dotContainer = document.querySelector('.dots');

// 方便查看幻灯片并构思
// const slide = document.querySelector('.slider--warpper')
// slide.style.transform = 'scale(0.5) translateX(-50%)'
// slide.style.overflow = 'visible'

let curSlide = 0; // 当前可见幻灯片
const maxSlide = slides.length; // 幻灯片总数量

// 创建控制器
const createDots = function () {
  slides.forEach(function (_, i) {
    // 将指定的文本解析为 Element 元素，并将结果节点插入到 DOM 树中的指定位置。比直接使用 innerHTML 操作更快。
    dotContainer.insertAdjacentHTML('beforeend', `<button class="dots__dot" data-slide="${i}"></button>`)
  })
};

// 给当前幻灯片对应的控制器按钮添加激活类
const activateDot = function (slide) {
  // 先移除所有激活
  document.querySelectorAll('.dots__dot').forEach(s => s.classList.remove('dots__dot--active'))
  // 然后给当前幻灯片对应的按钮添加激活
  document.querySelector(`.dots__dot[data-slide='${slide}']`).classList.add('dots__dot--active')
}
// 幻灯片横向滚动函数
const gotoSlide = function (slide) {
  // 遍历所有幻灯片，根据当前幻灯片下标，给所有幻灯片添加横向平移位置
  //  当前动作（点击次数） | 当前幻灯片下标 | 第一个幻灯片下标 | 第二个幻灯片下标 | 第三个幻灯片下标   
  //       啥也不做              0            0：0%             1：100%           2：200%                                        
  //       第一次                1            0：-100%          1：0%             2：100%                                        
  //       第二次                2            0：-200%          1：-100%          2：0%                                        
  //       第三次                0            0：0%             1：100%           2：200%                                        
  slides.forEach((s, i) => s.style.transform = `translateX(${100 * (i - slide)}%)`)
}

// 下一张幻灯片
const nextSlide = function () {
  if (curSlide === maxSlide - 1) {
    // 如果当前幻灯片是最后一张，就换成第一张
    curSlide = 0
  } else {
    //  否则继续下一张 
    curSlide++
  }
  gotoSlide(curSlide); // 调用幻灯片滚动函数
  activateDot(curSlide); // 给当前幻灯片对应控制器添加激活样式
}

// 上一张幻灯片
const prevSlide = function () {
  if (curSlide === 0) {
    // 如果当前幻灯片是第一张，就换成最后一张
    curSlide = maxSlide - 1
  } else {
    //  否则继续上一张 
    curSlide--
  }
  gotoSlide(curSlide); // 调用幻灯片滚动函数
  activateDot(curSlide); // 给当前幻灯片对应控制器添加激活样式
}

// 初始位置：初始下标
// 0：0% 100% 200%
const init = function () {
  gotoSlide(curSlide); // 调用幻灯片滚动函数
  createDots(); // 创建控制器
  activateDot(curSlide); // 给当前幻灯片对应控制器添加激活样式
}
init()

// 点击次数: 0% 为当前可见内容
// 注意：点击次数要和下标区分开
// 1：-100% 0% 100%
// 2：-200% -100% 0%
// 3：0% 100% 200%
slideRight.addEventListener('click', nextSlide); // 下一张按钮（幻灯片右边的按钮）
slideLeft.addEventListener('click', prevSlide); // 上一张按钮（幻灯片左边的按钮）

// P189、构建滑块（幻灯片）组件(第2部分)
// 键盘左键上一张幻灯片，右键下一张幻灯片
document.addEventListener('keydown', function (e) {
  const { key } = e;
  key === 'ArrowRight' && nextSlide()
  key === 'ArrowLeft' && prevSlide()
})

// 使用事件委派设置控制器的点击事件
dotContainer.addEventListener('click', function (e) {
  const { classList, dataset } = e.target; // 解构
  // 当前点击控制器元素时
  if (classList.contains('dots__dot')) {
    gotoSlide(dataset.slide); // 调用幻灯片滚动函数
    activateDot(dataset.slide); // 给当前幻灯片对应控制器添加激活样式
  }
})






/////////////////////////////////////////////////
/////////////////////////////////////////////////
/////////////////////////////////////////////////

/*
// P174、选择、创建和删除元素
// 选择元素
console.log(document.documentElement);
console.log(document.head);
console.log(document.body);

const header = document.querySelector('.header');
const allSections = document.querySelectorAll('.section');
console.log(allSections); // NodeList(4) 节点集合

document.getElementById('section--1');
const allButtons = document.getElementsByTagName('button');
console.log(allButtons); // HTMLCollection(9) 元素集合

console.log(document.getElementsByClassName('btn')); // HTMLCollection(5)

// 创建和插入元素
const message = document.createElement('div'); // 创建一个div元素
message.classList.add("cookie-message");// 添加一个类名
// message.textContent = 'We use cookied for improved functionality and analytics'; // 添加文本内容
message.innerHTML = 'We use cookied for improved functionality and analytics <button class="btn btn--close-cookie">Got it!</button>'; // 添加html文本内容

// 将创建好的元素插入页面
// header.prepend(message); // 插到header子元素最前面
header.append(message); // 插到header子元素最后面
// header.append(message.cloneNode(true)); // 克隆一个message插到header子元素最后面

// header.before(message); // 插到header元素前面
// header.after(message); // 插到header元素后面

// 删除元素
document.querySelector('.btn--close-cookie').addEventListener('click', function (e) {
  e.preventDefault;
  // message.remove();
  // 等同于
  message.parentElement.removeChild(message);
})


// P175、样式、属性和类
// 样式（style: 内联样式）
message.style.backgroundColor = '#37383d'; // 背景色
message.style.width = '120%'; // 宽度

// 因为没设置内联样式的以下内容所以没有
console.log(message.style.color); // 无
console.log(message.style.height); // 无

// 获取style标签或者文件中的的样式
// console.log(getComputedStyle(message)); // 当前元素的所有样式
console.log(getComputedStyle(message).color); // rgb(187, 187, 187)
console.log(getComputedStyle(message).height); // 47.5px

// 将获取到的元素高度提取数字并且加40
message.style.height = Number.parseFloat(getComputedStyle(message).height, 10) + 40 + 'px'

// 修改文档样式：style文件中的root
document.documentElement.style.setProperty('--color-primary', 'orangered');

// 属性
// 获取属性值
const logo = document.querySelector('.nav__logo');
console.log(logo.alt); // Bankist logo
console.log(logo.className); // nav__logo

// 非标准的属性
console.log(logo.designer); // undefined
console.log(logo.getAttribute('designer')); // xiaojiu
logo.setAttribute('company', 'Bankist');

console.log(logo.src); // http://127.0.0.1:5500/13-Advanced-DOM-Bankist/starter/img/logo.png
console.log(logo.getAttribute('src')); // img/logo.png

const link = document.querySelector('.nav__link--btn');
console.log(link.href); // http://127.0.0.1:5500/13-Advanced-DOM-Bankist/starter/index.html?#
console.log(link.getAttribute('href')); // #

// 数据属性(以data开头的属性名)
console.log(logo.dataset.versionNumber); // 3.0

// 类
logo.classList.add('x', 'j'); // 添加
logo.classList.remove('x', 'j'); // 删除
logo.classList.toggle('x'); // 有就删除, 没有就添加
logo.classList.contains('x'); // 不包含

// 不要使用, 因为只创建一个类名
// logo.className = 'xiaojiu'; // 会覆盖之前的类名
*/

/*
// P177、事件类型和事件处理程序
const h1 = document.querySelector('h1');

const alertH1 = function (e) {
  alert("addEventListener: 你正在读标题！");
  h1.removeEventListener('mouseenter', alertH1); // 移除事件
}
// 方式一: addEventListener
h1.addEventListener('mouseenter', alertH1); // 设置事件

// 三秒后移除事件
// setTimeout(() => {
//   h1.removeEventListener('mouseenter', alertH1); // 移除事件
// }, 3000);

// 方式二: onmouseenter
// h1.onmouseenter = function (e) {
//   alert("onmouseenter: 你正在读标题！")
// }


// P179、实践中的事件传播
const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
const randomColor = () => `rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
// // console.log(randomColor());
// document.querySelector('.nav__link').addEventListener('click', function (e) {
//   this.style.backgroundColor = randomColor();
//   console.log('LINK', e.target, e.currentTarget);
// })
// document.querySelector('.nav__links').addEventListener('click', function (e) {
//   this.style.backgroundColor = randomColor();
//   console.log('CONTAINER', e.target, e.currentTarget);
// })
// document.querySelector('.nav').addEventListener('click', function (e) {
//   this.style.backgroundColor = randomColor();
//   console.log('NAV', e.target, e.currentTarget);
// })

// 事件冒泡
// LINK         nav__link    nav__link
// CONTAINER    nav__link    nav__links
// NAV          nav__link    nav

document.querySelector('.nav__link').addEventListener('click', function (e) {
  this.style.backgroundColor = randomColor();
  console.log('LINK', e.target, e.currentTarget);
})
document.querySelector('.nav__links').addEventListener('click', function (e) {
  this.style.backgroundColor = randomColor();
  console.log('CONTAINER', e.target, e.currentTarget);
})
document.querySelector('.nav').addEventListener('click', function (e) {
  this.style.backgroundColor = randomColor();
  console.log('NAV', e.target, e.currentTarget);
}, true)

// 事件捕获
// NAV          nav__link    nav
// LINK         nav__link    nav__link
// CONTAINER    nav__link    nav__links
*/

/*
// P181、DOM遍历
const h1 = document.querySelector('h1');

// 向下选择子元素
console.log(h1.querySelectorAll('.highlight')); // NodeList(2) [span.highlight, span.highlight]
// 节点可以是元素中任何类型，如文本元素等
// 节点
console.log(h1.childNodes); // NodeList(9) [text, comment, text, span.highlight, text, br, text, span.highlight, text]
// 元素
console.log(h1.children); // HTMLCollection(3) [span.highlight, br, span.highlight]
// 第一个和最后一个元素子元素
h1.firstElementChild.style.color = 'white';
h1.lastElementChild.style.color = 'orange';

// 向上选择父元素
// 节点
console.log(h1.parentNode); // div.header__title
// 元素
console.log(h1.parentElement); // div.header__title
// 选择器且离当前元素最近的祖先元素（也可以是当前元素本身）
h1.closest('header').style.background = 'var(--gradient-secondary)';
h1.closest('h1').style.background = 'var(--gradient-primary)';

// 横向选择兄弟元素
// 元素
// 前一个兄弟
console.log(h1.previousElementSibling); // null
// 后一个兄弟
console.log(h1.nextElementSibling); // h4
// 节点
console.log(h1.previousSibling);
console.log(h1.nextSibling);

// h1父元素的子元素，包括他自己
console.log(h1.parentElement.children); // HTMLCollection(4) [h1, h4, button.btn--text.btn--scroll-to, img.header__img]
[...h1.parentElement.children].forEach(el => {
  if (el !== h1) {
    el.style.transform = 'scale(0.5)'
  }
}); // 将存在h1父元素的子元素，除了h1都缩小
*/


// P190、生命周期DOM事件
// 当 HTML 文档完全解析，且所有延迟脚本（<script defer src="…"> 和 <script type="module">）下载和执行完毕后，会触发 DOMContentLoaded 事件。
// 它不会等待图片、子框架和异步脚本等其他内容完成加载。
document.addEventListener('DOMContentLoaded', function (e) {
  console.log(e);
});

// load 事件在整个页面及所有依赖资源如样式表和图片都已完成加载时触发。
// 它与 DOMContentLoaded 不同，后者只要页面 DOM 加载完成就触发，无需等待依赖资源的加载。
window.addEventListener('load', function (e) {
  console.log(e);
})

// 当浏览器窗口关闭或者刷新时，会触发 beforeunload 事件。
// 当前页面不会直接关闭，可以点击确定按钮关闭或刷新，也可以取消关闭或刷新。
// window.addEventListener('beforeunload', function (e) {
//   e.preventDefault();
//   console.log(e);
//   e.returnValue = '';
// })
// 建议少用


